#!/usr/bin/env python

import sys
import os.path
import torrentfile
from collections import OrderedDict

def args(num):
	def dec(func):
		def wrap(self, *args):
			try:
				args = list(args)
				while len(args) < num:
					args.append(raw_input("%d+> " % (len(args) + 1)))
				return func(self, *args)
			except KeyboardInterrupt:
				print "<ESCAPED>"
				return
			except EOFError:
				print
				return
		return wrap
	return dec

class TEditMenu(object):
	def __init__(self, filn=None):
		self.tfile = None
		self.menu = OrderedDict([
			("a", (self.addTracker, "Add trackers\nTakes at least one argument.")),
			("c", (self.comment, "Change comment")),
			("d", (self.delTracker, "Delete tracker\nCan take a single argument: the number of tracker in the announce list to\ndelete, numbered from 1.")),
			("f", (self.files, "Print files list")),
			("g", (self.creator, "Change creator name")),
			("h", (self.opts, "Display help")),
			("l", (self.load, "Load torrent from file")),
			("m", (self.creation, "Change creation date\nTakes one argument, which must be seconds since 1 Jan 1970, 00:00:00 UTC")),
			("p", (self.meta, "Print metadata")),
			("q", (self.quit, "Quit")),
			("t", (self.tracker, "Change main tracker\nNote that if the tracker list is present, the main tracker is ignored.")),
			("w", (self.write, "Write torrent"))
		])

	
	def loaded(func):
		"""Function decorator to check if a file has been loaded"""
		def wrap(self, *args):
			if not self.tfile:
				print "No file loaded"
			else:
				return func(self, *args)
		return wrap

	def prompt(self):
		try:
			p = raw_input(">> ").split()
		except EOFError:
			print
			self.quit()
		if p:
			if p[0][0] in self.menu:
				self.menu[p[0][0]][0](*p[1:])

	@loaded
	@args(1)
	def addTracker(self, *args):
		args = filter(None, args)
		if args:
			if self.tfile.announceList:
				self.tfile.announceList += list(args)
			else:
				self.tfile.announceList = list(args)
	
	@loaded
	@args(1)
	def comment(self, *args):
		args = filter(None, args)
		self.tfile.comment = " ".join(args) if args else None
	
	@loaded
	def delTracker(self, *args):
		if self.tfile.announceList and len(self.tfile.announceList):
			maxnum = len(self.tfile.announceList)
			if args:
				sel = args[0]
			else:
				padnum = len("%s" % (maxnum + 1))
				for i, v in enumerate(self.tfile.announceList):
					pad = "%%%dd : %s" % (padnum, v)
					print pad % (i + 1)
				err = True
				while err:
					d = raw_input(" #> ")
					if d == "all":
						break
					elif d == "":
						return
					try:
						d = int(d)
						if d < 1 or d > maxnum:
							raise ValueError
					except ValueError:
						print "Select a number from 1 to %d" % maxnum
					else:
						err = False
				sel = d

			if sel == "all":
				self.tfile.announceList = None
				return

			try:
				sel = int(sel)
				del self.tfile.announceList[sel - 1]
			except ValueError:
				print "Invalid number `%d'" % sel
			if not self.tfile.announceList:
				self.tfile.announceList = None
		else:
			print "No trackers in the announce list"

	@loaded
	def files(self, *args):
		if "length" in self.tfile.info:
			print "%d    %s" % (self.tfile.size, self.tfile.info["name"])
		elif "files" in self.tfile.info:
			maxlen = 0
			flist = []
			for f in self.tfile.info["files"]:
				maxlen = max(maxlen, len("%s" % f["length"]))
				flist.append((f["length"], os.path.join(*f["path"])))
			for line in flist:
				pad = "%%%dd   %%s" % maxlen
				print pad % line
	
	@loaded
	@args(1)
	def creator(self, *args):
		args = filter(None, args)
		self.tfile.creator = " ".join(args) if args else None
	
	@args(1)
	def load(self, *args):
		try:
			with open(args[0]) as inf:
				self.tfile = torrentfile.TorrentFile(inf)
		except IOError as (errno, strerror):
			print "Oops! %s on `%s'" % (strerror, args[0])

	@loaded
	@args(1)
	def creation(self, *args):
		args = filter(None, args)
		if not args:
			self.tfile.creationDate = None
		else:
			try:
				self.tfile.creationDate = int(args[0])
			except ValueError:
				print "Date must be integer seconds since 1 Jan 1970, 00:00:00 UTC"

	@loaded
	def meta(self, *args):
		print "\n".join(self.tfile.describe())

	def quit(self, *args):
		sys.exit()
	
	@loaded
	@args(1)
	def tracker(self, *args):
		args = filter(None, args)
		if not(args) or not(len(args[0])):
			print "Tracker must not be empty"
		else:
			self.tfile.announce = args[0]
	
	@loaded
	@args(1)
	def write(self, *args):
		fn = args[0]
		if os.path.exists(fn):
			check = raw_input("File exists. Overwrite [y/N]? ")
			if check[0].lower() != "y":
				print "Not overwriting file."
				return
		try:
			with open(fn, "w") as ouf:
				ouf.write(self.tfile.toString())
		except IOError as (errno, strerr):
			print "Oops! %s on `%s'" % (strerr, fn)

	def opts(self, *args):
		if args and len(args[0]) and args[0][0] in self.menu:
			print self.menu[args[0][0]][1]
		else:
			for o in self.menu:
				print " %s\t%s" % (o, self.menu[o][1].split("\n")[0])
		#print " a\tAdd tracker"
		#print " c\tChange comment"
		#print " d\tDelete tracker"
		#print " g\tChange creator name"
		#print " h\tDisplay help"
		#print " l\tLoad torrent"
		#print " m\tChange creation date"
		#print " p\tPrint metadata"
		#print " q\tQuit"
		#print " t\tChange main tracker"
		#print " w\tWrite torrent"

if __name__ == "__main__":
	iface = TEditMenu()
	if len(sys.argv) > 1:
		iface.load(sys.argv[1])
	while True:
		iface.prompt()
